//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler
// FILE:            syntax.cpp
// AUTHOR:          Vladimir Gumenuk
// DATE:            21-Mar-2008
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"

int do_assignment_call( SYMBOLLIST symList, SymbolRef Func, string csVarName );

//------------------------------------------------------------------------
// helper: check the end of each case statement - can be: ... break; } OR ... } break; 
//------------------------------------------------------------------------
int do_case_end( SYMBOLLIST symList, int bNeedCloseBlk )
{
    int bNeedBrake = TRUE; // assume that we need it

    Token Tok = lex_GetToken( symList );
    if( Tok.m_dwTokenCode == tk_case || Tok.m_dwTokenCode == tk_default ) { // this is the case when ending break is processed in main_statement
        if( bNeedCloseBlk ) { // just check this
            x_error( ERR_EXPECTED_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
        lex_PutBack();
        return XORT_OK;
    }

    if( Tok.m_dwTokenCode == tk_break ) // case "... break; }"
    {
        Tok = lex_GetToken( symList ); // check for final ';'
        if( Tok.m_dwTokenCode == tk_semicolon )
        {
            bNeedBrake = FALSE; // got finale brake;
            if( bNeedCloseBlk )
            {
                Tok = lex_GetToken( symList );
                if( Tok.m_dwTokenCode == tk_blkclose )
                {
                    bNeedCloseBlk = FALSE; // got ended }
                    return XORT_OK;
                } else {
                    x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
            } else {
                return XORT_OK;
            }
        } else { 
            x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    if( bNeedCloseBlk )
    {
        if( Tok.m_dwTokenCode == tk_blkclose ) // case "... } break;"
        {
            bNeedCloseBlk = FALSE;
            Tok = lex_GetToken( symList ); // check for final '}' "brake" must be present
            if( Tok.m_dwTokenCode == tk_break ) 
            {
                Tok = lex_GetToken( symList ); // check for final ';'
                if( Tok.m_dwTokenCode == tk_semicolon )
                {
                    return XORT_OK;
                } else {
                    x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
            } else {
                // not in this time, break can be absent, can be processed in the main_statent, x_error( ERR_MISSING_BREAK, Tok.m_dwLine, Tok.m_dwPos );
                lex_PutBack();
                return XORT_OK;
            }
        } else {
            x_error( ERR_EXPECTED_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    if( Tok.m_dwTokenCode == tk_blkclose ) { // this case when we need the final switch{ } closing block
        if( !bNeedCloseBlk ) {
            lex_PutBack();
            return XORT_OK;
        } else {
            x_error( ERR_EXPR_SYNTAX, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    return XORT_OK;
}
//////////////////////////////////////////////////////////////////////////
// simple switch statement scheme
//     expr
//   ifz _Next1
//     ...
//     ...
//    goto _EndLabel
// _Next1:
//     expr2
//   ifz _Next2
//     ...
//     ...
//    goto _EndLabel
// _Next2:
//     expr3
//   ifz _Next3
//     ...
//     ...
//    goto _EndLabel
// _Next3:
//     ...
//     ...
// _EndLabel:
//------------------------------------------------------------------------
// no optimization - switch generated as a sequence of if - else if :(!
// TODO: FIXME! This construction is not supported well...
// case attr_import:
// case attr_module:
// case attr_name:
//     ++iCount;
//     break;
// default:
//     break;
//------------------------------------------------------------------------
int do_switch( SYMBOLLIST symList, SymbolRef Func )
{
    int iRet, bDefaultGot, bNeedCloseBlk;
    dword dwNumEntries;
    word wEndSwitchLabel, wEndCaseLabel;
    wEndSwitchLabel = get_NextLabel();
    dwNumEntries = 0;
    bDefaultGot = FALSE;

    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthopen ) {
        x_error( ERR_MISSING_PARENTHOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Symbol vSwitchValue;
    iRet = get_expr( symList, vSwitchValue, Func, getNULLSymbol(), FALSE );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthclose ) {
        x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkopen ) {
        x_error( ERR_MISSING_BLKOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Symbol dummyProc;  // sometimes there can be 'return' in switch, so, init dummy proc with real function type
    dummyProc.Init( sk_proc, "dummyProcForSwitchSTMT", Func.m_dwType, 0, 0, NULL, NULL, 0 );

    do { // get case value
        bNeedCloseBlk = FALSE; // reset flag that we expect '}' inside case x: { }

        Tok = lex_GetToken( symList );
        if( Tok.m_TT == tt_stmt ) {

            if( Tok.m_dwTokenCode == tk_case ) { // case:

                wEndCaseLabel = get_NextLabel();
                gen_dup( Func ); // duplicate switch value

                Symbol vConstant; // TODO: add check - expression must be constant!
                iRet = get_expr( symList, vConstant, Func, getNULLSymbol(), FALSE );
                if( iRet != XORT_OK ) 
                    return iRet;
                
                Tok = lex_GetLastToken();
                if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_colon ) {
                    x_error( ERR_MISSING_COLON, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }

                iRet = gen_ifneq( Func, vSwitchValue, vConstant, wEndCaseLabel );
                if( iRet != XORT_OK ) 
                    return iRet;

                Tok = lex_GetToken( symList );
                if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkopen ) {
                    bNeedCloseBlk = TRUE;
                } else {
                    lex_PutBack();
                }

                gen_enter( Func );
                ++dwNumEntries;

                iRet = do_main_statement( symList, Func, FALSE, 0, wEndSwitchLabel, dwNumEntries, FALSE, tk_switch );
                if( iRet != XORT_OK ) {
                    return iRet;
                }

                iRet = do_case_end( symList, bNeedCloseBlk ); // check the end sequence
                if( iRet != XORT_OK )
                    return iRet;

                --dwNumEntries;
                gen_leave( Func, TRUE );
                gen_label( Func, wEndCaseLabel );

            } else if( Tok.m_dwTokenCode == tk_default ) { // default:
                if( bDefaultGot ) {
                    x_error( ERR_DEFAULT_ALREADY_GOT, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
                bDefaultGot = TRUE;

                Tok = lex_GetToken( symList );
                if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_colon ) {
                    x_error( ERR_MISSING_COLON, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }

                Tok = lex_GetToken( symList );
                if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkopen ) {
                    bNeedCloseBlk = TRUE;
                } else {
                    lex_PutBack();
                }

                gen_enter( dummyProc );
                ++dwNumEntries;

                iRet = do_main_statement( symList, dummyProc, FALSE, 0, wEndSwitchLabel, dwNumEntries, FALSE, tk_switch );
                if( iRet != XORT_OK )
                    return iRet;

                iRet = do_case_end( symList, bNeedCloseBlk ); // check the end sequence
                if( iRet != XORT_OK )
                    return iRet;

                --dwNumEntries;
                gen_leave( dummyProc, TRUE );
            } else {
                x_error( ERR_UNEXPECTED_TOKEN, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        } else if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkclose ) {
            break;
        } else {
            x_error( ERR_UNEXPECTED_TOKEN, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    } while( iRet == XORT_OK );

    Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkclose ) {
        x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    if( bDefaultGot ) {
        x_copyCode( Func, dummyProc ); // make sure, that default block is always last :)
    }

    gen_label( Func, wEndSwitchLabel );
    gen_drop( Func );
    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_if( SYMBOLLIST symList, SymbolRef Func, word wStartLabel, word wExitLabel, word wEndLabel, dword dwNumEntries )
{
    word wSkipLabel  = get_NextLabel();
    word wEntryLabel = get_NextLabel();

    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthopen ) {
        x_error( ERR_MISSING_PARENTHOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Symbol vResult;
    int iRet = get_expr( symList, vResult, Func, getNULLSymbol(), TRUE );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthclose ) {
        x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    iRet = gen_ifz( Func, vResult, wSkipLabel );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    int bNeedCloseBlk = FALSE;
    Tok = lex_GetToken( symList );
    if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkopen ) {
        bNeedCloseBlk = TRUE;
    } else {
        lex_PutBack();
    }

    gen_label( Func, wEntryLabel );
    gen_enter( Func );
    ++dwNumEntries;

    iRet = do_main_statement( symList, Func, FALSE, wStartLabel, wExitLabel, dwNumEntries, !bNeedCloseBlk, tk_if );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    if( bNeedCloseBlk )
    {
        Tok = lex_GetLastToken();
        if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkclose ) {
            x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    --dwNumEntries;
    gen_leave( Func, TRUE );

    Tok = lex_GetToken( symList ); // look ahead if we have else - if construct
    if( Tok.m_TT == tt_stmt && Tok.m_dwTokenCode == tk_else ) {
        gen_goto( Func, wEndLabel ); // in case condition succeed, must skip all other 'else' statements
    } else {
        gen_label( Func, wEndLabel );
        iRet = 0; // !!! special case - mean that final end label generated for this if-elseif sequence
    }
    lex_PutBack();

    gen_label( Func, wSkipLabel ); // generate label to skip this if-block
    return iRet;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_else( SYMBOLLIST symList, SymbolRef Func, word wStartLabel, word wExitLabel, word wEndLabel, dword dwNumEntries )
{
    int iRet;
    int bNeedCloseBlk = FALSE;

    Token Tok = lex_GetToken( symList );

    if( Tok.m_TT == tt_stmt && Tok.m_dwTokenCode == tk_if ) {

        return do_if( symList, Func, wStartLabel, wExitLabel, wEndLabel, dwNumEntries );

    } else {
        
        if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkopen )
            bNeedCloseBlk = TRUE; // otherwise single statement expected - like this one :)
        else
            lex_PutBack();

        gen_enter( Func );
        ++dwNumEntries;

        iRet = do_main_statement( symList, Func, FALSE, wStartLabel, wExitLabel, dwNumEntries, !bNeedCloseBlk, tk_else );
        if( iRet != XORT_OK ) {
            return iRet;
        }

        if( bNeedCloseBlk ) {
            Tok = lex_GetLastToken();
            if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkclose ) {
                x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        }

        --dwNumEntries;
        gen_leave( Func, TRUE );
        gen_label( Func, wEndLabel ); // apply final our EndLabel!
        // the only one time for now :)
        return 0; // NOTE!!! - 0 - special return from this function! indicating that final EndLabel generated
    }
    
    x_error( ERR_UNEXPECTED_TOKEN, Tok.m_dwLine, Tok.m_dwPos );
    return ERR_SYNTAX;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_while( SYMBOLLIST symList, SymbolRef Func, dword dwNumEntries )
{
    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthopen ) {
        x_error( ERR_MISSING_PARENTHOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    word wStartLabel = get_NextLabel();
    word wExitLabel  = get_NextLabel(); // each wExitLabel marks end of the stack scope
    gen_label( Func, wStartLabel );

    Symbol vResult;
    int iRet = get_expr( symList, vResult, Func, getNULLSymbol(), TRUE );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthclose ) {
        x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    iRet = gen_ifz( Func, vResult, wExitLabel );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    int bNeedCloseBlk = FALSE;
    Tok = lex_GetToken( symList );
    if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkopen ) {
        bNeedCloseBlk = TRUE;
    } else {
        lex_PutBack();
    }

    gen_enter( Func );
    ++dwNumEntries;
    iRet = do_main_statement( symList, Func, FALSE, wStartLabel, wExitLabel, 1, !bNeedCloseBlk, tk_while );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    if( bNeedCloseBlk )
    {
        Tok = lex_GetLastToken();
        if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkclose ) {
            x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    gen_leave( Func, TRUE ); --dwNumEntries;
    gen_goto( Func, wStartLabel );
    gen_label( Func, wExitLabel );
    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_do_while( SYMBOLLIST symList, SymbolRef Func, dword dwNumEntries )
{
    int bSingle;
    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkopen ) {
        bSingle = FALSE;
    } else {
        bSingle = TRUE;
    }

    word wStartLabel = get_NextLabel();
    word wExitLabel  = get_NextLabel();

    gen_label( Func, wStartLabel );
    gen_enter( Func ); ++dwNumEntries;

    int iRet = do_main_statement( symList, Func, FALSE, wStartLabel, wExitLabel, 1, bSingle, tk_do );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    gen_leave( Func, TRUE ); --dwNumEntries;

    if( !bSingle ) {
        Tok = lex_GetLastToken();
        if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkclose ) {
            x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_stmt || Tok.m_dwTokenCode != tk_while ) {
        x_error( ERR_MISSING_WHILE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthopen ) {
        x_error( ERR_MISSING_PARENTHOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Symbol vResult;
    iRet = get_expr( symList, vResult, Func, getNULLSymbol(), TRUE );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthclose ) {
        x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_semicolon ) {
        x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    iRet = gen_ifnz( Func, vResult, wStartLabel );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    gen_label( Func, wExitLabel );
    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_for( SYMBOLLIST symList, SymbolRef Func, dword dwNumEntries )
{
    int iRet, bNeedCloseBlk;

    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthopen ) {
        x_error( ERR_MISSING_PARENTHOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Tok = lex_GetToken( symList );
    SymbolRef Var = FindSymbol( symList, Tok.m_csVal, FALSE );
    if( Var.isNULL() || ( Var.m_SymKind != sk_var && Var.m_SymKind != sk_arg && Var.m_SymKind != sk_proc ) ) {
        x_error( ERR_IDENT_ISNOT_VAR, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    iRet = do_assignment_call( symList, Func, Tok.m_csVal ); // first expr
    if( iRet != XORT_OK ) {
        return iRet;
    }

    word wStartLabel = get_NextLabel();
    word wExitLabel  = get_NextLabel();
    gen_label( Func, wStartLabel );

    Symbol vResult;
    iRet = get_expr( symList, vResult, Func, getNULLSymbol(), TRUE ); // get condition expression
    if( iRet != XORT_OK ) {
        return iRet;
    }

    Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_semicolon ) {
        x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    iRet = gen_ifz( Func, vResult, wExitLabel );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    // check, possible bug, resulting to this code in 3rd expression:
    /* from ReadString method:
    00000036-[ip:00000035]:        load.s.u4    S[4]                   ;[00000438]  load i //       for( i = 0; i < dwLength; ++i )
    00000037-[ip:00000036]:        inc.u4
    00000038-[ip:00000037]:        dup                  <<<--- ???, CHECKED, SEEMS OK, removed in optimizer...
    00000039-[ip:00000038]:        store.s.u4    S[4]
    0000003A-[ip:00000039]:        leave                               ;[0000043B]         } - generated in the end of this method
    */
    Symbol vDummyFunc; // generate 3 expression code into dummy proc, copy it latter.
    vDummyFunc.Init( sk_proc, "dummyProc", 0, 0, 0, NULL, NULL, 0 );
    vResult.Zero();
    iRet = get_expr( symList, vResult, vDummyFunc, getNULLSymbol(), FALSE ); // get 3 expr
    if( iRet != XORT_OK ) {
        return iRet;
    }

    Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthclose ) {
        x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    bNeedCloseBlk = FALSE;
    Tok = lex_GetToken( symList );
    if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkopen ) {
        bNeedCloseBlk = TRUE;
    } else {
        lex_PutBack();
    }

    gen_enter( Func ); ++dwNumEntries;

    iRet = do_main_statement( symList, Func, FALSE, wStartLabel, wExitLabel, 1, !bNeedCloseBlk, tk_for );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    if( bNeedCloseBlk )
    {
        Tok = lex_GetLastToken();
        if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkclose ) {
            x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    x_copyCode( Func, vDummyFunc ); // finally copy code that does 3 expression
    gen_leave( Func, TRUE ); --dwNumEntries;
    gen_goto( Func, wStartLabel );
    gen_label( Func, wExitLabel );
    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_break( SYMBOLLIST symList, SymbolRef Func, word wExitLabel, dword dwNumEntries )
{
    int iRet = lex_match( symList, tt_delim, tk_semicolon, FALSE );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    if( wExitLabel == 0 )
    {
        Token Tok = lex_GetLastToken();
        x_error( ERR_INTERNAL_COMPILER, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_INTERNAL;
    }

    while( dwNumEntries ) {
        gen_leave( Func, FALSE ); // This leave is for: { break; }. It can be optimized.
        --dwNumEntries;
    }

    gen_goto( Func, wExitLabel );
    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_continue( SYMBOLLIST symList, SymbolRef Func, word wStartLabel, dword dwNumEntries )
{
    int iRet = lex_match( symList, tt_delim, tk_semicolon, FALSE );
    if( iRet != XORT_OK )
        return iRet;

    if( wStartLabel == 0 )
    {
        Token Tok = lex_GetLastToken();
        x_error( ERR_INTERNAL_COMPILER, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_INTERNAL;
    }

    while( dwNumEntries ) {
        gen_leave( Func, FALSE ); // This leave is for: { break; }. It can be optimized.
        --dwNumEntries;
    }

    gen_goto( Func, wStartLabel );
    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_return( SYMBOLLIST symList, SymbolRef Func )
{
    int iRet = ERR_SYNTAX;
    Symbol vResult;
    vResult.Zero();

    // check for simple return;
    Token Tok = lex_GetToken( symList );

    if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_semicolon )
    {
        vResult.m_dwType = t_v;
        iRet = gen_ret( Func, Func, vResult );
        
    } else {
        lex_PutBack();

        iRet = get_expr( symList, vResult, Func, getNULLSymbol(), FALSE );
        if( iRet == XORT_OK ) // gen return code
        {
            Tok = lex_GetLastToken();
            if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_semicolon ) {
                x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }

            if( Func.m_dwType == t_void ) {
                x_error( ERR_VOID_FUNC_RETURN_VAL, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }

            iRet = gen_ret( Func, Func, vResult );
        }
    }

    return iRet;
}
//------------------------------------------------------------------------
// Generates the code to call target procedure. May be invoked from the expression analyzer
//------------------------------------------------------------------------
int do_callproc( SYMBOLLIST symList, SymbolRef Func, SymbolRef ProcToCall, int bInExpr, SymbolRef Object )
{
    int iRet = XORT_OK; 
    int bCloseParethGot = FALSE;
    dword dwNumArgs = 0;    // the number of arguments
    int bUnspecArgsCount = ( ProcToCall.m_dwFlags & f_unspecnumargs ) ? TRUE : FALSE;
    int bObjImported = FALSE;

    if( ProcToCall.m_pOwner && ( isObjectImported( DEREF(ProcToCall.m_pOwner) ) || MEMBER_PTR(ProcToCall.m_pOwner)m_dwFlags & f_export_obj ) ) {
        bObjImported = TRUE;
    }

    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthopen ) {
        x_error( ERR_MISSING_PARENTHOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    SYMBOL_LIST argCodeList;   // symbols that contains the code to get arguments on the stack, used for procedures with unspecified number of args

#ifdef CPP_COMPILER
    SYMBOL_LIST::iterator theIter = ProcToCall.m_listMembers.end();
    theIter--; // skip local scope marker
    symbolref Arg = ( theIter == NULL ) ? NULL : (Symbol*)theIter; // for cpp compilation
    if( Arg )
    {
#else
    SYMBOL_LISTIterator theIter = ProcToCall.m_listMembers.end();
    theIter.prev(); // skip local scope marker
    Symbol Arg = theIter.prev();
    if( Arg )
    {
#endif
        while( !bCloseParethGot  ) // load arguments to the stack
        {
            // this is post-iteration check :)
            if( !Arg && !bUnspecArgsCount ) { // if this is not a function with unspecified number of arguments
                x_error( ERR_INVALID_NUM_PARAMS, Tok.m_dwLine, Tok.m_dwPos );
                x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }

            Symbol vResult; // get argument
            Symbol PTR dummyProc NEW_OBJECT( Symbol );
            MEMBER_PTR(dummyProc) Init( sk_proc, "dummyProc", 0, 0, 0, NULL, NULL, 0 );

            if( bUnspecArgsCount ) { // call expression analyzer to load argument to the stack
                iRet = get_expr( symList, vResult, DEREF(dummyProc), getNULLSymbol(), FALSE );
                if( iRet == XORT_OK ) {
                    argCodeList.push_front( dummyProc );
                }
            } else {
                iRet = get_expr( symList, vResult, Func, getNULLSymbol(), FALSE );
            }

            if( iRet != XORT_OK )
                return iRet;
            
            Tok = lex_GetLastToken();
            if( Tok.m_TT != tt_delim ) {
                x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            } else if( Tok.m_dwTokenCode == tk_parenthclose ) {
                bCloseParethGot = TRUE;
            } else if( Tok.m_dwTokenCode != tk_coma ) {
                x_error( ERR_MISSING_COMA, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }

            // check for possible conversion:
            if( Arg && ( vResult.m_dwType != MEMBER_PTR(Arg)m_dwType ) && ( MEMBER_PTR(Arg)m_dwType < t_p ) && ( vResult.m_SymKind != sk_nullptr ) ) {
                if( MEMBER_PTR(Arg)m_csName.Compare( "$" ) != 0 ) {
                    iRet = gen_convert( bUnspecArgsCount ? DEREF(dummyProc) : Func, DEREF(Arg), vResult );
                    if( iRet != XORT_OK ) {
                        return iRet;
                    }
                }
            }

            // Place to check argument as exported to native module object. If it is, then need to use pack instruction
            if( bObjImported && vResult.m_dwType >= t_p && vResult.m_dwType <= t_system ) {
                // so, we are calling the native procedure on imported object with some xort complex object as argument. Need pack instruction
                iRet = gen_pack( Func, vResult );
                if( iRet != XORT_OK ) {
                    return iRet;
                }
            }
            ++dwNumArgs; // inc number of arguments

#ifdef CPP_COMPILER
            theIter--;
            Arg = theIter == NULL ? NULL : (Symbol*)theIter; //ProcToCall.m_listMembers.prev(); // for cpp compilation
#else
            Arg = theIter.prev(); // NULL can be returned, no special checks needed
#endif
        }
    }

    if( bUnspecArgsCount ) { // need to put it on the stack for such procedures, the procedure must know how handle them.
        
        if( argCodeList.size() > 0 ) { // copy code that loads arguments on the stack in cdecl order
            argCodeList.reset_to_begin();
            symbolref PTR pArgCode = argCodeList.next();
            while( pArgCode ) {
                x_copyCode( Func, DEREF( DEREF(pArgCode) ) );
                pArgCode = argCodeList.next();
            }
        }

        XortElement x; x.bType = t_u1; x._u1 = dwNumArgs; // so, the number of arguments is limited to 0xFF :)
        gen_loadConst( Func, x );
    } else { // check if we've got exact number of arguments as declared
        if( dwNumArgs < ProcToCall.m_dwArgumentsCount ) {
            x_error( ERR_INSUFF_NUM_ARGS, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        } else if( dwNumArgs > ProcToCall.m_dwArgumentsCount ) {
            x_error( ERR_INVALID_NUM_PARAMS, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    if( Object.isNULL() ) { // Need invoke. Invocation like object.Method is now generated only in expression analyzer.
        // The case when one object method invokes other method from the same object was not handled at all.
        // This is the attempt to handle this case as well...
        if( ( ProcToCall.m_pOwner && Func.m_pOwner ) && ( MEMBER_PTR(ProcToCall.m_pOwner)m_csName.Compare( MEMBER_PTR(Func.m_pOwner)m_csName ) == 0 ) ) {
            iRet = gen_invoke_ti( Func, ProcToCall );
        } else { // ... generate normal function call...
            iRet = gen_call( Func, ProcToCall );
        }
    }

    if( iRet == XORT_OK ) {
        if( !bInExpr && ProcToCall.m_dwType != t_void ) {
            gen_drop( Func );
        }
    }

    if( bCloseParethGot ) {
        Tok = lex_GetLastToken();
    } else {
        Tok = lex_GetToken( symList );
    }

    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_parenthclose ) {
        x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    if( !bInExpr ) // check for semicolon only if we have simple call like func(); not as a part of expression
    {
        Tok = lex_GetToken( symList );
        if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_semicolon ) {
            x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    return iRet;
}
//------------------------------------------------------------------------
// possible: var = ...; var.mem = ...; var.func();...
//------------------------------------------------------------------------
int do_assignment_call( SYMBOLLIST symList, SymbolRef Func, string csVarName )
{
    int iRet = 0;
    int bComplexObj = FALSE;

    SymbolRef Var = FindSymbol( symList, csVarName, FALSE );
    if( Var.m_SymKind == sk_proc ) {
        return do_callproc( symList, Func, Var, FALSE, getNULLSymbol() );
    }

    SymbolRef Type = FindType( symList, Var.m_dwType );
    if( Type.isNULL() ) {
        Token Tok = lex_GetLastToken();
        x_error( ERR_UNKNOWN_TYPE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim ) {
        x_error( ERR_EXPECTED_OPERATOR_ASSIGN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    // This dummyProc is used as a placeholder for generated code inside expression analyzer
    Symbol dummyProc, vDerefResult;
    dummyProc.Init( sk_proc, "dummyProc", 0, 0, 0, NULL, NULL, 0 );
    vDerefResult.Zero();

    if( Tok.m_dwTokenCode == tk_ptr ) // process assignment to obj.member1[.member2]* = 
    {
        bComplexObj = TRUE;
        iRet = exp_mem_ptr( symList, vDerefResult, dummyProc, Var ); // returned code gets members! 
        if( iRet != XORT_OK ) { // So, this expression is still dont know what will be the next - get ot put, and by default it generates the code for get.xx.
            return iRet;        // This is corrected later, by deleting last instruction.
        }

        Tok = lex_GetLastToken();
    }

    dword op = Tok.m_dwTokenCode;

    if( x_isAssignOp( op ) ) // =, +=, /= falls into this category
    {
        if( bComplexObj ) {
            if( vDerefResult.m_SymKind == sk_proc ) {
                x_error( ERR_CANNOT_ASGN_TO_PROC, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            } else if( vDerefResult.m_dwType == t_void ) {
                x_error( ERR_VOID_FUNC_CANNOTBE_PART_EXPR, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        }
 
        if( op != tk_assign ) { // well, it is assignment: +=, |=, *=, etc...
            if( bComplexObj ) {
                x_copyCode( Func, dummyProc ); // obj.m_member += ...
            } else {
                gen_load( Func, Var ); // x += 1, generates the following: load x; load 1; add; store x;
            }
        }

        Symbol vResult; // This gets the result for left part of assignment expression...
        iRet = get_expr( symList, vResult, Func, Var, FALSE );
        if( iRet != XORT_OK ) { 
            return iRet;
        }

        Tok = lex_GetLastToken(); // Should end with ';'
        if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_semicolon ) {
            x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        byte bCode = x_code_from_tok( op ); // gets the instruction code from token code
        if( bCode != 0 ) { // means that this is something like += ...
            if( bComplexObj ) {
                iRet = gen_arith( bCode, Func, vDerefResult, vResult );
            } else {
                iRet = gen_arith( bCode, Func, Var, vResult );
            }
        } // else we have simple assignment

        if( iRet == XORT_OK ) {
            if( bComplexObj ) {
                if( vResult.m_dwType != vDerefResult.m_dwType ) {
                    iRet = gen_convert( Func, vDerefResult, vResult );
                }

                if( iRet == XORT_OK ) {
                    dummyProc.removeLastInstr(); // remove last get.p instruction. It is generated by default in expression analyzer.
                    x_copyCode( Func, dummyProc );
                    iRet = gen_member_put( Func, vDerefResult, vResult );
                }
            } else {
                if( Var.m_dwFlags & f_const ) {
                    x_error( ERR_LVALUE_IS_CONSTANT, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
                iRet = gen_assign( Func, Var, vResult );
            }
        }
    } else if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_semicolon && bComplexObj ) {
        x_copyCode( Func, dummyProc ); // seems to be a member method call, ...YES(19.04.2013), obj.Method()
        // and it looks like result is unused, because there is no assignment...
        if( vDerefResult.m_SymKind == sk_proc && vDerefResult.m_dwType != t_void ) { // check this and drop result from the stack
            gen_drop( Func );
        }
    } else {
        x_error( ERR_EXPECTED_OPERATOR_ASSIGN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    return iRet;
}
//------------------------------------------------------------------------
// The only prefix operations are supported!: ++x --x
//------------------------------------------------------------------------
int do_inc_dec( SYMBOLLIST symList, SymbolRef Func, byte bCode )
{
    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_ident ) {
        x_error( ERR_EXPECTED_IDENT, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    SymbolRef Var = FindSymbol( symList, Tok.m_csVal, FALSE );
    if( Var.isNULL() ) {
        x_error( ERR_UNDECLARED_IDENTIFIER, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    if( Var.m_SymKind != sk_arg && Var.m_SymKind != sk_var ) {
        x_error( ERR_INCDEC_NOT_SUPP_FORCOMPLEX, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    if( Var.m_dwType == t_void || Var.m_dwType == t_r4 || Var.m_dwType == t_r8 || Var.m_dwType >= t_p ) {
        x_error( ERR_INCDEC_NOT_SUPP_FORTHISTYPE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    int iRet = gen_inc_dec( bCode, Func, Var );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim && Tok.m_dwTokenCode != tk_semicolon ) {
        x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    return XORT_OK;
}
//------------------------------------------------------------------------
// This is one of the most important functions. It parses everything that
// can be between brakets { ... } inside the function body.
// symList - local list of symbols for this proc, normally it belongs to Func
// Func - proc where code is generated
//------------------------------------------------------------------------
int do_main_statement( SYMBOLLIST symList, SymbolRef Func, int bMainScope, word wStartLabel, word wExitLabel, dword dwNumEntries, int bSingle, dword dwStmtCode )
{
    int iRet, bRetGenerated;
    word wEndElseIfLabel;
    iRet = XORT_OK;
    bRetGenerated = FALSE;
    wEndElseIfLabel = 0;
    iRet = XORT_OK;

    OpenLocalScope( symList, Func, FALSE );
    do
    {
        Token Tok = lex_GetToken( symList );

        if( Tok.m_TT == tt_modifier )
        {
            if( Tok.m_dwTokenCode == tk_const ) {
                Tok = lex_GetToken( symList );
                if( Tok.m_TT != tt_typename ) {
                    x_error( ERR_CONST_DECLARAYION, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
                string csUnused;
                iRet = do_var_proc( symList, Tok.m_dwTokenCode, Func, f_const, csUnused );
            } else {
                return ERR_INTERNAL;
            }
        }
        else if( Tok.m_TT == tt_typename ) // local variable declaration
        {
            string csUnused;
            iRet = do_var_proc( symList, Tok.m_dwTokenCode, Func, 0, csUnused );
        }
        else if( Tok.m_TT == tt_stmt ) // statement
        {
            if( Tok.m_dwTokenCode == tk_if ) {
                wEndElseIfLabel = get_NextLabel();
                iRet = do_if( symList, Func, wStartLabel, wExitLabel, wEndElseIfLabel, dwNumEntries );
                if( iRet == 0 ) { // this is the only case when do_xxx function can return zero!
                    wEndElseIfLabel = 0;
                    iRet = XORT_OK;
                } // else ??
            } else if( Tok.m_dwTokenCode == tk_else ) {
                if( wEndElseIfLabel == 0 ) {
                    x_error( ERR_ELSE_WITHOUT_IF, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
                iRet = do_else( symList, Func, wStartLabel, wExitLabel, wEndElseIfLabel, dwNumEntries );
                if( iRet == 0 ) { // this is the only case when do_xxx function can return zero!
                    wEndElseIfLabel = 0;   // final EndLabel generated!!!
                    iRet = XORT_OK;
                } // error? or we are still inside some nested if's
            } else if( Tok.m_dwTokenCode == tk_while ) {
                iRet = do_while( symList, Func, dwNumEntries );
            } else if( Tok.m_dwTokenCode == tk_for ) {
                iRet = do_for( symList, Func, dwNumEntries );
            } else if( Tok.m_dwTokenCode == tk_do ) {
                iRet = do_do_while( symList, Func, dwNumEntries );
            } else if( Tok.m_dwTokenCode == tk_break ) {
                iRet = do_break( symList, Func, wExitLabel, dwNumEntries );
            } else if( Tok.m_dwTokenCode == tk_continue ) {
                iRet = do_continue( symList, Func, wStartLabel, dwNumEntries );
            } else if( Tok.m_dwTokenCode == tk_return ) {
                iRet = do_return( symList, Func );
                bRetGenerated = TRUE;
            } else if( Tok.m_dwTokenCode == tk_switch ) {
                iRet = do_switch( symList, Func );
            } else if( Tok.m_dwTokenCode == tk_case || Tok.m_dwTokenCode == tk_default ) {
                if( dwStmtCode == tk_switch ) { // case & default will be processed on the upper level
                    lex_PutBack();
                    break;
                } else {
                    x_error( ERR_CASE_WITHOUT_SWITCH, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
            }
        }
        else if( Tok.m_TT == tt_ident ) // assignment expression or function call
        {
            SymbolRef Var = FindSymbol( symList, Tok.m_csVal, FALSE );
            if( Var.isNULL() || ( Var.m_SymKind != sk_var && Var.m_SymKind != sk_arg && Var.m_SymKind != sk_proc ) ) {
                x_error( ERR_IDENT_ISNOT_VAR, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }

            iRet = do_assignment_call( symList, Func, Tok.m_csVal );
        }
        else if( Tok.m_TT == tt_delim )
        {
            if( Tok.m_dwTokenCode == tk_inc ) {
                iRet = do_inc_dec( symList, Func, p_inc );
            } else if( Tok.m_dwTokenCode == tk_dec ) {
                iRet = do_inc_dec( symList, Func, p_dec );
            } else  if( Tok.m_dwTokenCode == tk_blkclose ) {
                if( !bRetGenerated && bMainScope ) {
                    iRet = gen_ret2( Func, Func );
                } else if( dwStmtCode == tk_switch ) {
                    lex_PutBack(); // process '}' on the upper level
                }
                break;
            } else {
                x_error( ERR_EXPECTED_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
                iRet = ERR_SYNTAX;
            }
        } else {
            x_error( ERR_DECLARAYION_SYNTAX, Tok.m_dwLine, Tok.m_dwPos );
            iRet = ERR_SYNTAX;
        }

        if( bSingle && iRet == XORT_OK ) {
            Tok = lex_GetLastToken();
            if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_semicolon ) {
                break;
            } else {
                x_error( ERR_EXPECTED_SINGLE_LINE_STMT, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        }
    } while( iRet == XORT_OK );

    CloseLocalScope( symList, Func );
    return iRet;
}
//------------------------------------------------------------------------
// parse function declaration
//------------------------------------------------------------------------
int do_function( SYMBOLLIST symList, SymbolRef Func, int bHasForward, SymbolRef pOwner, dword dwFlags )
{
    int iRet;
    int iArgGot = FALSE;
    ResetArgIdx();
    ResetStackVarIdx();

    //DbgPrint( "do_function() -> ENTER" );
    do // get arguments
    {
        Token Tok = lex_GetToken( symList );
        if( Tok.m_TT == tt_typename ) // argument
        {
            dword dwType = Tok.m_dwTokenCode;
            if( dwFlags & f_import_obj || dwFlags & f_import_proc ) // validate type.
            {
                if( !validate_native_type( symList, dwType ) )
                    return ERR_SYNTAX;
            }

            Tok = lex_GetToken( symList );
            if( Tok.m_TT != tt_ident ) {
                x_error( ERR_EXPECTED_ARG_NAME, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }

            SymbolRef Arg = FindSymbol( Func.m_listMembers, Tok.m_csVal, TRUE );
            if( !Arg.isNULL() ) {
                if( bHasForward ) {
                    if( Arg.m_dwType != dwType ) {
                        x_error( ERR_ARG_ALREADY_DECL_WITH_DIFTYPE, Tok.m_dwLine, Tok.m_dwPos );
                        return ERR_SYNTAX;
                    }
                } else {
                    x_error( ERR_ARG_ALREADY_DECL, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
            } else { // case when forward declaration differs
                if( bHasForward ) {
                    x_error( ERR_ARG_FORWARD_DECL_DIFFERS, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
            }

            string csArgName;
            csArgName.Assign( Tok.m_csVal ); // name

            Tok = lex_GetToken( symList );
            if( Tok.m_TT == tt_delim && (Tok.m_dwTokenCode == tk_parenthclose || Tok.m_dwTokenCode == tk_coma) )
            {
                if( !bHasForward ) {
                    AddSymbol( Func.m_listMembers, sk_arg, csArgName, dwType, NULL, pOwner, 0 );
                }
                if( Tok.m_dwTokenCode == tk_parenthclose ) {
                    iArgGot = 1;
                }
            } else {
                x_error( ERR_MISSING_PARENTHCLOSE, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        } else if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_elipsis ) {

            Func.m_dwFlags |= f_unspecnumargs;
            AddSymbol( Func.m_listMembers, sk_arg, "$", t_void, NULL, getNULLSymbol(), 0 ); // indicates the unspecified number of args!
            Tok = lex_GetToken( symList );
            if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_parenthclose )
            {
                iArgGot = TRUE;
            } else {
                x_error( ERR_FUNC_DECL_ERROR, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        } else if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_parenthclose ) {
            iArgGot = TRUE;
        } else {
            x_error( ERR_FUNC_DECL_ERROR, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    } while( !iArgGot );

    if( !bHasForward ) { // assign it only once
        Func.m_dwArgumentsCount = Func.m_listMembers.size() - 1;
		if( !(Func.m_dwFlags & f_unspecnumargs) ) { // invert arguments indexes only for normal procedures that have pascall CC.
			RevertArgIndexes( Func.m_listMembers ); // invert them only once!
		}
    }

    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim ) {
        x_error( ERR_FUNC_DECL_ERROR, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    if( Tok.m_dwTokenCode == tk_blkopen ) // begin of function body
    {
        iRet = do_main_statement( symList, Func, TRUE, 0, 0, 0, FALSE, 0 );
        if( iRet != XORT_OK ) {
            return iRet;
        }
    } else if( Tok.m_dwTokenCode != tk_semicolon ) { // function declaration
        x_error( ERR_FUNC_DECL_ERROR, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    //DbgPrint( "do_function() -> LEAVE" );
    return XORT_OK;
}
//------------------------------------------------------------------------
// Calculates the constant expression
// int bAddSymbol - if false function will try to find symbol first
//------------------------------------------------------------------------
int do_const_var( SYMBOLLIST symList, dword dwTypeCode, string csName, dword dwFlags, int bAddSymbol )
{
    int iRet;
    Symbol vResult;
    iRet = get_expr( symList, vResult, getNULLSymbol(), getNULLSymbol(), FALSE );
    if( iRet != XORT_OK ) {
        return iRet;
    }

    Token Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_semicolon ) {
        if( dwFlags & f_enumconst ) {
            if( Tok.m_dwTokenCode != tk_coma && Tok.m_dwTokenCode != tk_blkclose ) {
                x_error( ERR_ENUM_SYNTAX, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        } else {
            x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    if( ( vResult.m_dwFlags == f_const ) && 
        ( vResult.m_SymKind == sk_var || vResult.m_SymKind == sk_integer || vResult.m_SymKind == sk_real || vResult.m_SymKind == sk_nullptr ) )
    {
        if( vResult.m_dwType != dwTypeCode ) {
            XortElement x;
            iRet = x_convert_type( dwTypeCode, x, vResult.m_Value );
            if( iRet != XORT_OK ) {
                x_error( ERR_CONST_EXPR_TYPES_MISMATCH, Tok.m_dwLine, Tok.m_dwPos );
                return iRet;
            }
            x_copyelement( vResult.m_Value, x );
        }

        if( bAddSymbol ) {
            SymbolRef Var = AddSymbol( symList, sk_var, csName, dwTypeCode, NULL, getNULLSymbol(), dwFlags );
            x_copyelement( Var.m_Value, vResult.m_Value );
            if( vResult.m_dwLiteralIdx != 0 ) {
                Var.m_dwLiteralIdx = vResult.m_dwLiteralIdx;
            }
        } else {
            SymbolRef Var = FindSymbol( symList, csName, TRUE ); // try to find symbol
            if( Var.isNULL() ) {
                x_error( ERR_UNDECLARED_IDENTIFIER, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
            x_copyelement( Var.m_Value, vResult.m_Value );
            if( vResult.m_dwLiteralIdx != 0 ) {
                Var.m_dwLiteralIdx = vResult.m_dwLiteralIdx;
            }
        }
    } else {
        x_error( ERR_EXPECTED_CONST_EXPR, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    return XORT_OK;
}
//------------------------------------------------------------------------
// Enum parsing
//------------------------------------------------------------------------
int do_enum( SYMBOLLIST symList )
{
    int iRet;

    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_ident ) {
        x_error( ERR_EXPECTED_IDENT, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    SymbolRef symCheck = FindSymbol( symList, Tok.m_csVal, FALSE );
    if( !symCheck.isNULL() ) {
        x_error( ERR_IDENT_ALREADY_DECLARED, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    // compiler treats enum types as int, add it
    SymbolRef baseType = FindType( symList, t_s4 ); // build-in
    AddAliasName( baseType, Tok.m_csVal );

    Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkopen ) {
        x_error( ERR_MISSING_BLKOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    int iDefaultVal = 0; // default enum value starts from 0
    int bExpectedNext = TRUE;

    do 
    {
        Tok = lex_GetToken( symList );
        if( Tok.m_TT != tt_ident ) {
            x_error( ERR_DECLARAYION_SYNTAX, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        SymbolRef symNameCheck = FindSymbol( symList, Tok.m_csVal, TRUE );
        if( !symNameCheck.isNULL() ) {
            x_error( ERR_IDENT_ALREADY_DECLARED, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        string csName;
        csName.Assign( Tok.m_csVal ); // enum const name;

        Tok = lex_GetToken( symList );
        if( Tok.m_TT == tt_delim )
        {
            if( Tok.m_dwTokenCode == tk_assign ) { // enum with initializer
                iRet = do_const_var( symList, t_s4, csName, f_const | f_enumconst, TRUE );
                if( iRet != XORT_OK ) {
                    return iRet;
                }

                SymbolRef enumConst = FindSymbol( symList, csName, FALSE );
                iDefaultVal = enumConst.m_Value._s4 + 1; // enum constant added, use its default value

                Tok = lex_GetLastToken(); // check if we have done with this
                if( Tok.m_dwTokenCode == tk_blkclose ) {
                    bExpectedNext = FALSE;
                }

            } else if( Tok.m_dwTokenCode == tk_coma || Tok.m_dwTokenCode == tk_blkclose ) { // use default
                SymbolRef enumConst = AddSymbol( symList, sk_var, csName, t_s4, NULL, getNULLSymbol(), f_const | f_enumconst );
                enumConst.m_Value._s4 = iDefaultVal; ++iDefaultVal;
                enumConst.m_Value.bType = t_s4;

                if( Tok.m_dwTokenCode == tk_blkclose ) {
                    bExpectedNext = FALSE;
                }
            } else {
                x_error( ERR_ENUM_SYNTAX, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        }

        if( bExpectedNext ) {
            Tok = lex_GetToken( symList );
            if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkclose ) {
                bExpectedNext = FALSE;
            } else {
                lex_PutBack();
            }
        }

    } while( bExpectedNext );

    Tok = lex_GetLastToken();
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkclose ) {
        x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }
    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int validate_native_type( SYMBOLLIST symList, dword dwTypeCode )
{
    SymbolRef Type = FindType( symList, dwTypeCode );

    if( ! ( Type.m_dwFlags & f_allowed_native ) )
    {
        Token Tok = lex_GetLastToken();
        x_error( ERR_TYPE_NATIVELY_NOT_ALLOWED, Tok.m_dwLine, Tok.m_dwPos );
        return FALSE;
    }

    return TRUE;
}
//------------------------------------------------------------------------
// Variable or procedure
// SymbolRef Func - can be procedure, so the arguments are expected or
//                  object, so there can be member function or variables
//------------------------------------------------------------------------
int do_var_proc( SYMBOLLIST symList, dword dwTypeCode, SymbolRef Func, dword dwFlags, StringRef csNameOut )
{
    int iRet = 0;
    int bIsVar = 0;
    int bExpectNext = 0;     // can be multiple variable declaration

    if( dwFlags & f_import_obj || dwFlags & f_import_proc ) // validate type.
    {
        if( !validate_native_type( symList, dwTypeCode ) )
            return ERR_SYNTAX;
    }

    //DbgPrint( "do_var_proc() -> ENTER" );
    do
    {
        Token Tok = lex_GetToken( symList );
        if( Tok.m_TT != tt_ident ) {
            x_error( ERR_DECLARAYION_SYNTAX, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        SymbolRef pForwardProc = FindSymbol( symList, Tok.m_csVal, TRUE );
        if( !pForwardProc.isNULL() ) {
            if( pForwardProc.m_SymKind == sk_proc && pForwardProc.m_Code.count() == 0 ) {
                if( pForwardProc.m_dwType != dwTypeCode ) {
                    x_error( ERR_FUNC_DECLARED_WITH_DIFF_RETTYPE, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                } // else Allow forward procedure declaration!
            } else {
                x_error( ERR_IDENT_ALREADY_DECLARED, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        }

        if( ( dwFlags & f_proc_expected ) && ( !pForwardProc.isNULL() ) ) {
            x_error( ERR_FORWARD_PROC_WITHATTR, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        string csName;
        csName.Assign( Tok.m_csVal ); // var or procedure name
        
        Tok = lex_GetToken( symList );
        if( ( dwFlags & f_proc_expected ) && ( Tok.m_dwTokenCode != tk_parenthopen ) ) {
            x_error( ERR_PROC_DECL_EXPECTED, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        csNameOut.Assign( csName ); // assign name to output parameter
        if( Tok.m_TT == tt_delim )
        {
            if( dwFlags & f_const ) { // constant assignment

                if( ( dwFlags & f_proc_expected ) && ( Tok.m_dwTokenCode != tk_parenthopen ) ) { // proc expected
                    x_error( ERR_PROC_DECL_EXPECTED, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }

                if( Tok.m_dwTokenCode != tk_assign ) {
                    x_error( ERR_EXPECTED_OPERATOR_ASSIGN, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                } else {
                    iRet = do_const_var( symList, dwTypeCode, csName, dwFlags, TRUE );
                    return iRet;
                }
            } else { // runtime expression assignment
                if( Tok.m_dwTokenCode == tk_assign ) {

                    if( ( dwFlags & f_proc_expected ) && ( Tok.m_dwTokenCode != tk_parenthopen ) ) { // proc expected
                        x_error( ERR_PROC_DECL_EXPECTED, Tok.m_dwLine, Tok.m_dwPos );
                        return ERR_SYNTAX;
                    }

                    SymbolRef Var = AddSymbol( symList, sk_var, csName, dwTypeCode, NULL, Func, 0 );
                    if( !Func.isNULL() && Func.m_SymKind == sk_proc && Var.m_dwStorage == cSTORAGE_STACK ) {
                        gen_StackVarMark( Func, Var.m_iIndex );
                        gen_loadZero( Func, dwTypeCode, FALSE ); // generate local variable on stack
                        lex_PutBack(); // put back last '=' it will be checked in next function
                        iRet = do_assignment_call( symList, Func, csName );
                        return iRet; // compiler expects that there will be only 1 expression like: a = b + c;
                    } else { // support static initializers:
                        iRet = do_const_var( symList, dwTypeCode, csName, f_const, FALSE );
                        if( iRet != XORT_OK ) {
                            x_error( ERR_STATIC_INITIALIZERS, Tok.m_dwLine, Tok.m_dwPos );
                            return ERR_SYNTAX;
                        }
                        return XORT_OK;
                    }

                    bExpectNext = FALSE;
                }
            }
    
            if( Tok.m_dwTokenCode == tk_parenthopen ) // function declaration
            {
                if( !Func.isNULL() && Func.m_SymKind == sk_proc ) {
                    x_error( ERR_NESTED_PROC, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }

                if( pForwardProc.isNULL() ) { // verify: looks like this is not needed - verified, NEEDED!
                    SymbolRef FuncLoc = AddSymbol( symList, sk_proc, csName, dwTypeCode, NULL, Func, 0 );
                    AddSymbol( FuncLoc.m_listMembers, sk_scopelocal, getLocalMarker(), t_void, ADDROF(symList), getNULLSymbol(), 0 );

                    iRet = do_function( FuncLoc.m_listMembers, FuncLoc, FALSE, Func, dwFlags );
                    if( iRet != XORT_OK ) {
                        return iRet;
                    }
                } else {
                    iRet = do_function( pForwardProc.m_listMembers, pForwardProc, TRUE, Func, dwFlags );
                    if( iRet != XORT_OK ) {
                        return iRet;
                    }
                }

                bExpectNext = FALSE;
            } else if( Tok.m_dwTokenCode == tk_coma )  { // multiple variable declaration
                SymbolRef Var = AddSymbol( symList, sk_var, csName, dwTypeCode, NULL, Func, 0 );
                if( !Func.isNULL() && Func.m_SymKind == sk_proc && Var.m_dwStorage == cSTORAGE_STACK ) {
                    gen_StackVarMark( Func, Var.m_iIndex );
                    gen_loadZero( Func, dwTypeCode, TRUE );
                }

                bIsVar = TRUE;
                bExpectNext = TRUE;
            } else if( Tok.m_dwTokenCode == tk_semicolon ) { // end of var declaration
                SymbolRef Var = AddSymbol( symList, sk_var, csName, dwTypeCode, NULL, Func, 0 );
                if( !Func.isNULL() && Func.m_SymKind == sk_proc && Var.m_dwStorage == cSTORAGE_STACK ) {
                    gen_StackVarMark( Func, Var.m_iIndex );
                    gen_loadZero( Func, dwTypeCode, TRUE );
                }

                bExpectNext = FALSE;
            } else {
                x_error( ERR_DECLARAYION_SYNTAX, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        }
    } while( bExpectNext );

    //DbgPrint( "do_var_proc() -> LEAVE - OK" );
    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_object( SYMBOLLIST symList, ATTRARRAY arAttributes, StringRef csNameOut )
{
    ResetLocalIdx();

    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_ident && Tok.m_TT != tt_typename )
    {
        x_error( ERR_DECLARAYION_SYNTAX, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    SymbolRef Test = FindSymbol( symList, Tok.m_csVal, FALSE );
    if( !Test.isNULL() )
    {
        // test if this object empty. if yes - this is the forward object declaration
        if( Test.m_SymKind != sk_obj || Test.m_listMembers.size() != 0 ) {
            x_error( ERR_IDENT_ALREADY_DECLARED, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    SymbolRef pObject = ( Test.isNULL() ) ? // ternary operator fixed
        AddSymbol( symList, sk_obj, Tok.m_csVal, GenNewTypeCode(), NULL, getNULLSymbol(), 0 ) :
        FindSymbol( symList, Tok.m_csVal, FALSE );

    // check that object may be imported from some native dll... or exported to it
    dword dwImportFlag = 0;
    string csImport, csExport;
    if( x_findAttribute( arAttributes, attr_import, csImport ) ) {
        if( csImport.Compare( "object" ) == 0 ) {
            pObject.m_dwFlags |= f_import_obj | f_allowed_native; // mark object as imported and allowed in native object method declarations...
            dwImportFlag = f_import_obj;
        } else {
            x_error( ERR_ATTRIBUTE_DECL, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    } else if( x_findAttribute( arAttributes, attr_export, csExport ) ) {
        if( csExport.Compare( "object" ) == 0 ) {
            pObject.m_dwFlags |= f_export_obj | f_allowed_native; // mark object as exported and allowed in native object method declarations...
            dwImportFlag = f_export_obj;
        } else {
            x_error( ERR_ATTRIBUTE_DECL, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
    }

    arAttributes.copy( pObject.m_arAttributes ); // attach attributes to the procedure

    Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim ) {
        x_error( ERR_MISSING_BLKOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    } else if( Tok.m_dwTokenCode == tk_semicolon ) { // this is forward object declaration!
        if( !Test.isNULL() ) {
            x_error( WRN_SECOND_OBJ_IGNORED, Tok.m_dwLine, Tok.m_dwPos );
        }
        return XORT_OK;
    }

//     if( Tok.m_dwTokenCode == tk_less ) { // < - template object declaration
//         Tok = lex_GetToken( symList );
//         if( Tok.m_TT == tt_stmt && Tok.m_dwTokenCode == tk_typename ) {
//             pObject.m_SymKind = sk_template; // template definition
//         }
//         // else - template expansion
//         // TODO: lex_GetToken on the final step - to be a correct input for next statement!
//     }

    if( Tok.m_dwTokenCode == tk_blkopen ) // { - simple object declaration - members are followed
    {   
        AddSymbol( pObject.m_listMembers, sk_scopelocal, getLocalMarker(), t_void, ADDROF(symList), getNULLSymbol(), 0 );
        
        do // parse members
        {
            int iRet;
            Tok = lex_GetToken( pObject.m_listMembers );
            if( Tok.m_TT == tt_typename ) // variable declaration or procedure
            {
                if( ( dwImportFlag & f_export_obj ) && ( Tok.m_dwTokenCode >= t_system ) ) { // build-in system types doesn't support pack instruction
                    x_error( ERR_TYPE_NOT_ALLOWED_IN_EXPORT_OBJ, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }
                string csUnused;
                iRet = do_var_proc( pObject.m_listMembers, Tok.m_dwTokenCode, pObject, dwImportFlag, csUnused );
                if( iRet != XORT_OK ) {
                    return iRet;
                }
            } else if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_blkclose ) {
                csNameOut.Assign( pObject.m_csName );
                return XORT_OK; // another return - bad code...
            } else {
                x_error( ERR_EXPECTED_TYPENAME, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        } while( Tok.m_TT != tt_eof );

        x_error( ERR_UNEXPECTED_EOF, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    } else {
        x_error( ERR_MISSING_BLKOPEN, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_delim || Tok.m_dwTokenCode != tk_blkclose )
    {
        x_error( ERR_MISSING_BLKCLOSE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    csNameOut.Assign( pObject.m_csName );

    return XORT_OK;
}
//------------------------------------------------------------------------
// typedef oldtype newalias
//------------------------------------------------------------------------
int do_typedef( SYMBOLLIST symList )
{
    string csNewTypeName;
    dword dwTemplateCode;
    dwTemplateCode = 0;
    
    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT == tt_template ) { // for now only 2 build-in templates: array and list
        
        dwTemplateCode = Tok.m_dwTokenCode;

        Tok = lex_GetToken( symList );
        if( Tok.m_TT == tt_delim && Tok.m_dwTokenCode == tk_less ) { // template typename

            Tok = lex_GetToken( symList );
            if( Tok.m_TT == tt_typename ) { // for ex. typedef array<byte>

                SymbolRef pTemplateType = FindType( symList, Tok.m_dwTokenCode );
                if( pTemplateType.isNULL() ) {
                    return ERR_INTERNAL; // must be defined before anyway!
                }

                Tok = lex_GetToken( symList );
                if( Tok.m_TT != tt_delim && Tok.m_dwTokenCode != tk_greater ) {
                    x_error( ERR_MISSING_MISSING_GREATER, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }

                Tok = lex_GetToken( symList );
                if( Tok.m_TT != tt_ident ) {
                    x_error( ERR_EXPECTED_IDENT, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }

                csNewTypeName.Assign( Tok.m_csVal );

                Tok = lex_GetToken( symList );
                if( Tok.m_TT != tt_delim && Tok.m_dwTokenCode != tk_semicolon ) {
                    x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
                    return ERR_SYNTAX;
                }

                // template type declared
                BuildComplexType( symList, csNewTypeName, dwTemplateCode, pTemplateType );

            } else {
                x_error( ERR_EXPECTED_TYPENAME, Tok.m_dwLine, Tok.m_dwPos );
                return ERR_SYNTAX;
            }
        }
    } else if( Tok.m_TT == tt_typename ) {
        SymbolRef pBaseType = FindType( symList, Tok.m_dwTokenCode );
        if( pBaseType.isNULL() ) {
            return ERR_INTERNAL; // must be defined before anyway
        }

        Tok = lex_GetToken( symList );
        if( Tok.m_TT == tt_ident ) { // new alias name got
            csNewTypeName.Assign( Tok.m_csVal );
        } else {
            x_error( ERR_EXPECTED_IDENT, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        Tok = lex_GetToken( symList );
        if( Tok.m_TT != tt_delim && Tok.m_dwTokenCode != tk_semicolon ) {
            x_error( ERR_MISSING_SEMICOLON, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        // simple like: typedef int INTEGER;
        AddAliasName( pBaseType, csNewTypeName );

    } else {
        x_error( ERR_EXPECTED_TYPENAME, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int do_attributes( SYMBOLLIST symList, ATTRARRAY arAttributes )
{
    Token Tok = lex_GetToken( symList );
    if( Tok.m_TT != tt_attr ) {
        x_error( ERR_EXPECTED_ATTRIBUTE, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    do 
    {
        Attributes PTR attr NEW_OBJECT( Attributes );

        switch( Tok.m_dwTokenCode )
        {
        case tk_a_import:   MEMBER_PTR(attr)dwAttrCode = attr_import;   break;
        case tk_a_name:     MEMBER_PTR(attr)dwAttrCode = attr_name;     break;
        case tk_a_module:   MEMBER_PTR(attr)dwAttrCode = attr_module;   break;
        case tk_a_callconv: MEMBER_PTR(attr)dwAttrCode = attr_callconv; break;
        case tk_a_platform: MEMBER_PTR(attr)dwAttrCode = attr_platform; break;
        case tk_a_export:   MEMBER_PTR(attr)dwAttrCode = attr_export;   break;
        default:
            x_error( ERR_UNKNOWN_ATTRIBUTE, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        // get attribute value:
        Tok = lex_GetToken( symList );
        if( Tok.m_dwTokenCode != tk_parenthopen ) {
            x_error( ERR_ATTRIBUTE_DECL, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        Tok = lex_GetToken( symList );
        if( Tok.m_TT != tt_literal ) {
            x_error( ERR_ATTRIBUTE_DECL, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }

        MEMBER_PTR(attr)csAttrValue.Assign( Tok.m_csVal );

        Tok = lex_GetToken( symList );
        if( Tok.m_dwTokenCode != tk_parenthclose ) {
            x_error( ERR_ATTRIBUTE_DECL, Tok.m_dwLine, Tok.m_dwPos );
            return ERR_SYNTAX;
        }
        arAttributes.add( attr );
       
        Tok = lex_GetToken( symList ); // get next attribute of ]
    } while( Tok.m_dwTokenCode != tk_sqrbrclose );

    return XORT_OK;
}
//------------------------------------------------------------------------
// The following attributes are valid for objects:
// [import("object") name("MyFile") module("somenative.dll")] or
// [export("object")]
//------------------------------------------------------------------------
int validate_obj_attributes( ATTRARRAY arAttributes )
{
    int iImp = 0;
    int iMod = 0;
    int iName = 0;
    int iExp = 0;
    dword i;
    for( i = 0; i < arAttributes.count(); ++i )
    {
        AttributesRef pAttr = arAttributes.get(i);
        switch( MEMBER_PTR(pAttr)dwAttrCode )
        {                   
        case attr_import:
            if( MEMBER_PTR(pAttr)csAttrValue.Compare( "object" ) == 0 || MEMBER_PTR(pAttr)csAttrValue.Compare( "proc" ) == 0 )
                ++iImp;
            break;          
                            
        case attr_module:   
            if( ! ( MEMBER_PTR(pAttr)csAttrValue.IsEmpty() ) )
                ++iMod;       
            break;          
                            
        case attr_name:
            if( ! ( MEMBER_PTR(pAttr)csAttrValue.IsEmpty() ) )
                ++iName;
            break;

        case attr_export:
            if( MEMBER_PTR(pAttr)csAttrValue.Compare( "object" ) == 0 || MEMBER_PTR(pAttr)csAttrValue.Compare( "proc" ) == 0 )
                ++iExp;
            break;

        default:
            break;
        }
    }

    if( iImp == 0 && iExp == 0 )
    {
        Token Tok = lex_GetLastToken();
        x_error( ERR_ATTRIBUTE_DECL, Tok.m_dwLine, Tok.m_dwPos );
        return ERR_SYNTAX;
    }

    return XORT_OK;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int isObjectImported( SymbolRef obj )
{
    int bRet = FALSE;

    if( obj.m_arAttributes.count() )
    {
        string csAttr;
        if( x_findAttribute( obj.m_arAttributes, attr_import, csAttr ) )
        {
            if( x_findAttribute( obj.m_arAttributes, attr_module, csAttr ) )
            {
                bRet = TRUE;
            }
        }
    }

    return bRet;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------